﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Collections.Specialized;
using Aspose.Cells;
using ePlanet.Entities;
using System.Threading;

namespace FilesUpload
{
    public partial class DownloadManager : Form
    {
        public DownloadManager()
        {
            InitializeComponent();
            backgroundWorkerDownloadExportTemplate = new System.ComponentModel.BackgroundWorker();
            backgroundWorkerDownloadExportTemplate.WorkerReportsProgress = true;
            backgroundWorkerDownloadExportTemplate.WorkerSupportsCancellation = true;
            backgroundWorkerDownloadExportTemplate.DoWork += new DoWorkEventHandler(backgroundWorkerDownloadExportTemplate_DoWork);
            backgroundWorkerDownloadExportTemplate.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerDownloadExportTemplate_ProgressChanged);
            backgroundWorkerDownloadExportTemplate.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerDownloadExportTemplate_RunWorkerCompleted);
            backgroundWorkerDownloadFile = new System.ComponentModel.BackgroundWorker();
            backgroundWorkerDownloadFile.WorkerReportsProgress = true;
            backgroundWorkerDownloadFile.WorkerSupportsCancellation = true;
            backgroundWorkerDownloadFile.DoWork += new DoWorkEventHandler(backgroundWorkerDownloadFile_DoWork);
            backgroundWorkerDownloadFile.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerDownloadFile_ProgressChanged);
            backgroundWorkerDownloadFile.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerDownloadFile_RunWorkerCompleted);
        }

        private Queue<AttachmentItem> fileDownloads = new Queue<AttachmentItem>();
        //private List<AttachmentItem> errors = new List<AttachmentItem>();
        private AttachmentItem CurrentAttachmentInfo
        {
            get;
            set;
        }
        void backgroundWorkerDownloadExportTemplate_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.progressBarDownload.Value = 100;
            if (e.Cancelled)
            {
                ListFileItem item = new ListFileItem(this.CurrentAttachmentInfo.AttachmentInfo.Name, DownloadState.Cancel, string.Empty);
                this.lblLog.Items.Add(item);
            }
            if (e.Error != null)
            {
                ListFileItem item = new ListFileItem(this.CurrentAttachmentInfo.AttachmentInfo.Name, DownloadState.Error, e.Error.Message);
                this.lblLog.Items.Add(item);
            }
            else
            {
                ListFileItem item = new ListFileItem(this.CurrentAttachmentInfo.AttachmentInfo.Name, DownloadState.Sucess, ", 著录项信息导出");
                this.lblLog.Items.Add(item);

                this.ExcelSavePath = Path.Combine(this.CurrentAttachmentInfo.AttachmentInfo.SaveDirectory, this.CurrentAttachmentInfo.AttachmentInfo.Name);
                Workbook workbook = new Workbook();
                workbook.Open(this.ExcelSavePath);
                int rowIndex = 1;
                Cells cells = null; ;
                Cell cell = null;
                if (workbook.Worksheets.Count > 0)
                {
                    #region 原始导出方法
                    cells = workbook.Worksheets[0].Cells;
                    cell = cells[rowIndex, 0];
                    while (cell != null && cell.Value != null && !string.IsNullOrEmpty(cell.StringValue))
                    {
                        Cell dataFile = cells[rowIndex, 1];
                        if (dataFile.Value != null)
                        {
                            int count;
                            if (int.TryParse(dataFile.StringValue, out count))
                            {
                                if (count > 0)
                                {
                                    int counter = 1;
                                    dataFile = cells[rowIndex, 2];
                                    while (counter <= count)
                                    {
                                        if (dataFile.Value != null)
                                        {
                                            AttachmentInfo info = Newtonsoft.Json.JsonConvert.DeserializeObject<AttachmentInfo>(dataFile.StringValue);
                                            fileDownloads.Enqueue(new AttachmentItem(info, 0, rowIndex, 2));
                                        }
                                        counter++;
                                        dataFile = cells[++rowIndex, 2];
                                    }
                                    rowIndex--;
                                }
                            }
                        }
                        cell = cells[++rowIndex, 0];
                    }
                    rowIndex = 0;
                    #endregion

                    
                }
                if (workbook.Worksheets.Count > 1)
                {
                    cells = workbook.Worksheets[1].Cells;
                    cell = cells[rowIndex, 0];
                    while (cell != null && cell.Value != null && !string.IsNullOrEmpty(cell.StringValue))
                    {
                        Cell dataFile = cells[rowIndex, 1];
                        if (dataFile.Value != null)
                        {
                            int count;
                            if (int.TryParse(dataFile.StringValue, out count))
                            {
                                if (count > 0)
                                {
                                    int counter = 1;
                                    dataFile = cells[rowIndex, 2];
                                    while (counter <= count)
                                    {
                                        if (dataFile.Value != null)
                                        {
                                            AttachmentInfo info = Newtonsoft.Json.JsonConvert.DeserializeObject<AttachmentInfo>(dataFile.StringValue);
                                            fileDownloads.Enqueue(new AttachmentItem(info, 1, rowIndex, 2));
                                        }
                                        counter++;
                                        dataFile = cells[++rowIndex, 2];
                                    }
                                    rowIndex--;
                                }
                            }
                        }
                        cell = cells[++rowIndex, 0];
                    }
                }
                /*
                string fileRequestUrl = helper.GetArchiveExportHandlerPath() + "?UserId=" + this.UserId + "&CatalogId=" + this.CatalogId + "&Type=" + this.Type + "&RequestType=GetFileList";
                string queryStr = Newtonsoft.Json.JsonConvert.SerializeObject(dataIds);
                WebClient webClient = new WebClient();
                NameValueCollection varPost = new NameValueCollection();
                varPost.Add("data", queryStr);
                byte[] respons = webClient.UploadValues(fileRequestUrl, "POST", varPost);
                string responsStr = System.Text.Encoding.UTF8.GetString(respons);
                if(responsStr.StartsWith("Error:"))
                {
                    if (responsStr.Length > "Error:".Length)
                    {
                        MessageBox.Show("服务器发生错误：" + responsStr.Substring(responsStr.IndexOf("Error:")), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    else
                    {
                        MessageBox.Show("服务器发生错误", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
                attachmentInfos = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AttachmentInfo>>(responsStr);
                */
                if (fileDownloads.Count > 0)
                {
                    this.lblTotalCount.Text = fileDownloads.Count.ToString();
                    this.CurrentAttachmentInfo = fileDownloads.Dequeue();
                    backgroundWorkerDownloadFile.RunWorkerAsync();
                }
                else
                {
                    this.CurrentAttachmentInfo = null;
                    MessageBox.Show("导出完成");
                }
            }
        }

        void backgroundWorkerDownloadExportTemplate_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            /*
            if (e.ProgressPercentage >= 99)
            {
                this.progressBarDownload.Value = 99;
            }
            else
            {
                this.progressBarDownload.Value = e.ProgressPercentage;
            }
            UserState userState = e.UserState as UserState;
            this.lblCurrentFileSize.Text = (userState.CurrentSize / 1024.0 * 1024.0).ToString("F2") + "M/" + (userState.TotalSize / 1024.0 * 1024.0).ToString("F2") + "M";
            this.lblCurrentDownFileName.Text = userState.FileName;
            double second = userState.UserdTime.TotalSeconds;
            this.lblUsedTime.Text = second.ToString("F2") + "秒";
            if (second > 0)
            {
                lblSpeed.Text = (userState.CurrentSize / 1024.0 / second).ToString("0.00") + "KB/秒";
            }
            Application.DoEvents();
            */
        }

        void backgroundWorkerDownloadExportTemplate_DoWork(object sender, DoWorkEventArgs e)
        {
            string fileRequestUrl = helper.GetArchiveExportHandlerPath() + "?UserId=" + this.UserId + "&CatalogId=" + this.CatalogId + "&Type=" + this.Type + "&RequestType=TemplateFile" + "&DataId=" + this.ExcelImportTempPathUrl;
            this.DownloadFile(fileRequestUrl, this.txtSaveDirectory.Text, this.backgroundWorkerDownloadExportTemplate, e);
        }

        void backgroundWorkerDownloadFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.progressBarDownload.Value = 100;
            if (e.Cancelled)
            {
                ListFileItem item = new ListFileItem(this.CurrentAttachmentInfo.AttachmentInfo.Name, DownloadState.Cancel, string.Empty);
                this.lblLog.Items.Add(item);
            }
            if (e.Error != null)
            {
                this.lblErrorCount.Text = string.IsNullOrEmpty(this.lblErrorCount.Text) ? string.Concat(1) : string.Concat(int.Parse(this.lblErrorCount.Text) + 1);
                ListFileItem item = new ListFileItem(this.CurrentAttachmentInfo.AttachmentInfo.Name, DownloadState.Error, e.Error.Message);
                this.lblLog.Items.Add(item);
            }
            else
            {
                ListFileItem item = new ListFileItem(string.Concat(e.Result), DownloadState.Sucess, string.Empty);
                this.lblDownloadedCount.Text = string.IsNullOrEmpty(this.lblDownloadedCount.Text) ? string.Concat(1) : string.Concat(int.Parse(this.lblDownloadedCount.Text) + 1);
                this.lblLog.Items.Add(item);
                string saveFilePath = Path.Combine(this.CurrentAttachmentInfo.AttachmentInfo.SaveDirectory, this.CurrentAttachmentInfo.AttachmentInfo.Name);
                Workbook workbook = new Workbook();
                //修改附件地址
                workbook.Open(this.ExcelSavePath);
                workbook.Worksheets[this.CurrentAttachmentInfo.SheetIndex].Cells[this.CurrentAttachmentInfo.Row, this.CurrentAttachmentInfo.Column].PutValue(saveFilePath);
                workbook.Save(this.ExcelSavePath);
            }
            if (fileDownloads.Count > 0)
            {
                this.CurrentAttachmentInfo = fileDownloads.Dequeue();
                this.backgroundWorkerDownloadFile.RunWorkerAsync();
            }
            else
            {
                this.CurrentAttachmentInfo = null;
                MessageBox.Show("导出完成");
            }
        }

        void backgroundWorkerDownloadFile_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            UserState userState = e.UserState as UserState;
            if (e.ProgressPercentage >= 99)
            {
                this.progressBarDownload.Value = 99;
            }
            else
            {
                this.progressBarDownload.Value = e.ProgressPercentage;
            }

            this.lblCurrentFileSize.Text = (userState.CurrentSize / 1024.0 ).ToString("F2") + "KB/" + (userState.TotalSize / 1024.0 ).ToString("F2") + "KB";
            this.lblCurrentDownFileName.Text = this.CurrentAttachmentInfo.AttachmentInfo.Name;
            double second = userState.UserdTime.TotalSeconds;
            this.lblUsedTime.Text = second.ToString("F2") + "秒";
            if (second > 0)
            {
                lblSpeed.Text = (userState.CurrentSize / second).ToString("0.00") + "KB/秒";
            }
            //Application.DoEvents();
        }

        void backgroundWorkerDownloadFile_DoWork(object sender, DoWorkEventArgs e)
        {
            string fileRequestUrl = helper.GetArchiveExportHandlerPath() + "?UserId=" + this.UserId + "&CatalogId=" + this.CatalogId + "&Type=" + this.Type + "&RequestType=DataFile" + "&DataId=" + this.CurrentAttachmentInfo.AttachmentInfo.Id+"&DbHelper="+this.CurrentAttachmentInfo.AttachmentInfo.DbHelperString;
            this.DownloadFile(fileRequestUrl, this.txtSaveDirectory.Text, this.backgroundWorkerDownloadFile, e);
        }

        public string UserId { get; set; }

        public string ExcelImportTempPathUrl { get; set; }

        public string excelSavePath;
        public string ExcelSavePath
        {
            get
            {
                if (string.IsNullOrEmpty(excelSavePath))
                {
                    return Path.Combine(this.txtSaveDirectory.Text, Path.GetFileName(Uri.UnescapeDataString(this.ExcelImportTempPathUrl)));
                }
                else
                {
                    return this.excelSavePath;
                }
            }
            set
            {
                this.excelSavePath = value;
            }
        }

        public string CatalogId { get; set; }

        public string WebAddress { get; set; }

        /// <summary>
        /// Archive Or SingWell
        /// </summary>
        public string Type { get; set; }

        private BackgroundWorker backgroundWorkerDownloadExportTemplate;
        private BackgroundWorker backgroundWorkerDownloadFile;

        private void DownloadManager_Load(object sender, EventArgs e)
        {
            NameValueCollection nameValueTable = helper.GetQueryStringParameters();
            this.UserId = nameValueTable.Get("UserId");
            this.CatalogId = nameValueTable.Get("CatalogId");
            this.ExcelImportTempPathUrl = nameValueTable.Get("ExcelImportTempPath");
            this.WebAddress = nameValueTable.Get("WebAddress");
            this.Type = nameValueTable.Get("Type");

            //Type = "Archive";
            //UserId = "25174a50-795c-4f8e-b1dd-e3ce073fbc8d";
            //CatalogId = "3";
            //WebAddress = "http://localhost:6180/EOAU";
            //this.ExcelImportTempPathUrl = @"C:\Users\lenovo\Desktop\科学技术研究类+F.xls";

            if (string.IsNullOrEmpty(UserId) || string.IsNullOrEmpty(WebAddress) || string.IsNullOrEmpty(Type) || string.IsNullOrEmpty(CatalogId)||string.IsNullOrEmpty(ExcelImportTempPathUrl))
            {
                MessageBox.Show("程序打开时发生错误，请重新打开！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
            }
            btnSelectDirectory_Click(null, null);
        }

        private void btnSelectDirectory_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.ShowNewFolderButton = true;
            folderBrowserDialog.Description = "请选择导出文件存放目录";
            if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (!Directory.Exists(folderBrowserDialog.SelectedPath))
                {
                    MessageBox.Show("你选择的路径不存在，请重新选择！");
                    return;
                }
                this.txtSaveDirectory.Text = folderBrowserDialog.SelectedPath;
            }
        }

        DateTime downloadStart;
        private void btnDownload_Click(object sender, EventArgs e)
        {
            this.btnDownload.Enabled = false;
            this.btnSelectDirectory.Enabled = false;
            fileDownloads.Clear();
            downloadStart = DateTime.Now;
            string templateFileName = Path.GetFileName(Uri.UnescapeDataString(this.ExcelImportTempPathUrl));
            this.CurrentAttachmentInfo = new AttachmentItem() { AttachmentInfo = new AttachmentInfo() { Name = templateFileName } };
            backgroundWorkerDownloadExportTemplate.RunWorkerAsync();
        }
        
        private void DownloadFile(string url, string saveDirectory, BackgroundWorker worker, DoWorkEventArgs e)
        {
            try
            {
                HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
                WebResponse webRespon = httpReq.GetResponse();
                Stream s = webRespon.GetResponseStream();
                if (webRespon.ContentType == "text/plain")
                {
                    StreamReader sr = new StreamReader(s);
                    string responseStr = sr.ReadToEnd();
                    if (responseStr.Length > "Error:".Length)
                    {
                        throw new Exception("服务器发生错误:" + responseStr.Substring(responseStr.IndexOf("Error:")));
                    }
                    else
                    {
                        throw new Exception("服务器发生错误");
                    }
                }
                //int fileSize = int.Parse(webRespon.Headers["DataBaseFileSize"]);
                //string fileName = webRespon.Headers["DataBaseFileName"];
                int fileSize = this.CurrentAttachmentInfo.AttachmentInfo.FileSize;
                string fileName = this.CurrentAttachmentInfo.AttachmentInfo.Name;
                if (!string.IsNullOrEmpty(this.CurrentAttachmentInfo.AttachmentInfo.SaveDirectory))
                {
                    saveDirectory = Path.Combine(saveDirectory, this.CurrentAttachmentInfo.AttachmentInfo.SaveDirectory);
                }
                if (!Directory.Exists(saveDirectory))
                {
                    Directory.CreateDirectory(saveDirectory);
                }
                string filePath = Path.Combine(saveDirectory, fileName);
                string directoryName = Path.GetDirectoryName(filePath);
                string fileNameWithoutEx = Path.GetFileNameWithoutExtension(filePath);
                string fileNameEx = Path.GetExtension(filePath);
                string temp = filePath;
                int i = 0;
                while (File.Exists(temp))
                {
                    temp = Path.Combine(directoryName,fileNameWithoutEx + "_" + (++i)+fileNameEx);
                }
                filePath = temp;
                this.CurrentAttachmentInfo.AttachmentInfo.Name = Path.GetFileName(filePath);
                this.CurrentAttachmentInfo.AttachmentInfo.SaveDirectory = directoryName;
                using (FileStream fs = new FileStream(filePath, FileMode.Create))
                {
                    long offset = 0;
                    int bufferLength = 4096;
                    byte[] buffer = new byte[bufferLength];

                    DateTime startTime = DateTime.Now;
                    int size = s.Read(buffer, 0, buffer.Length);
                    while (size > 0)
                    {
                        if (worker.CancellationPending == true)
                        {
                            e.Cancel = true;
                            break;
                        }

                        fs.Write(buffer, 0, size);
                        offset += size;

                        UserState userState = new UserState(fileName, fileSize, offset / 1024, DateTime.Now - startTime);
                        worker.ReportProgress(userState.ProgressPercentage, userState);

                        size = s.Read(buffer, 0, bufferLength);
                    }
                    fs.Flush();
                    fs.Close();
                    fs.Dispose();
                }
                e.Result = fileName;
                return;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void btnExportLog_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (ListFileItem item in this.lblLog.Items)
            {
                if (item.State == DownloadState.Error)
                {
                    sb.AppendLine(item.Text + ": " + item.Msg);
                }
            }
            if (sb.Length == 0)
            {
                MessageBox.Show("文件全部导出成功");
                return;
            }
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.DefaultExt = "txt";
            saveFileDialog.Filter = "txt文件 (*.txt)|*.txt";
            saveFileDialog.FileName = "*.txt";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                using (StreamWriter sw = new StreamWriter(saveFileDialog.FileName, false))
                {
                    sw.Write(sb.ToString());
                    sw.Flush();
                    sw.Close();
                }
            }
        }
    }

    public class UserState
    {
        public string FileName { get; set; }
        public long TotalSize { get; set; }
        public long CurrentSize { get; set; }
        public int ProgressPercentage
        {
            get
            {
                if (this.TotalSize == 0)
                {
                    return 100;
                }
                return (int)(this.CurrentSize * 100.0 / this.TotalSize);
            }
        }
        public TimeSpan UserdTime { get; set; }
        public UserState(string fileName, long totalSize,long currentSize, TimeSpan userdTime)
        {
            this.FileName = fileName;
            this.TotalSize = totalSize;
            this.CurrentSize = currentSize;
            this.UserdTime = userdTime;
        }
    }

    public class ListFileItem
    {
        public string Text { get; set; }
        public DownloadState State {get;set;}
        public string Msg { get; set; }
        public ListFileItem(string fileName, DownloadState state, string errorMsg)
        {
            this.Text = fileName;
            this.State = state;
            this.Msg = errorMsg;
        }
        public override string ToString()
        {
            if (this.State == DownloadState.Cancel)
            {
                return this.Text+": "+"取消下载"+Msg;
            }
            else if (this.State == DownloadState.Error)
            {
                return this.Text + ": " + "下载错误: "+Msg;
            }
            else
            {
                return this.Text + ": " + "下载成功"+Msg;
            }
        }
    }

    public enum DownloadState
    {
        Sucess,
        Cancel,
        Error
    }

    public class AttachmentItem
    {
        public AttachmentInfo AttachmentInfo { get; set; }
        public int SheetIndex { get; set; }
        public int Row { get; set; }
        public int Column { get; set; }
        public AttachmentItem()
        { }
        public AttachmentItem(AttachmentInfo info, int sheetIndex, int row, int column)
        {
            this.AttachmentInfo = info;
            this.SheetIndex = sheetIndex;
            this.Row = row;
            this.Column = column;
        }
    }
}
